package com.cdqidi.service;

import java.io.IOException;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cdqidi.entity.PayOrder;
import com.cdqidi.entity.PayResult;
import com.cdqidi.entity.User;
import com.cdqidi.util.RedisMgr;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import com.jfinal.plugin.activerecord.Record;

public class WeiXinPayService {
	
	private WeiXinPayService(){
		
	}
	
	private static class SingletonHolder {
		private static WeiXinPayService INSTANCE = new WeiXinPayService();
	}

	public static WeiXinPayService getInstance() {
		return SingletonHolder.INSTANCE;
	}
	
	/**
	 * 保存发送到微信的订单
	 * @param orderId
	 * @param ip
	 * @param orderContent
	 * @param time_start
	 * @param user
	 */
	public void saveWxOrder(String orderId,String ip,String orderContent,Date time_start,User user) {
		Integer days=user.getDays();	
		Record r = new Record();
			r.set("orderId", orderId);
			r.set("mchId", user.getMchId());
			r.set("personid", user.getParid());
			r.set("mobile", user.getMobile());
			if (null != user.getMonth()) {
				switch (user.getMonth()) {
				case 1:
					days = 30;
					break;
				case 3:
					days = 90;
					break;
				case 6:
					days = 180;
					break;
				case 12:
					days = 365;
					break;
					
				}
			}
			if(null==days||days<1) {
				throw new RuntimeException("month参数错误");
			}
			r.set("orderDays", days);
			r.set("payAmount", user.getAmount());
			r.set("ipAddress", ip);
			r.set("orderContent", orderContent);
			r.set("time_start", time_start);
			r.set("orgid", user.getSchoolid());
			r.set("pwxorgid", user.getPayWxorgid());
			r.set("wxorgid", user.getWxorgid());
			r.set("openid", user.getPayOpenid());
			r.set("stuid", user.getStuid());
			r.set("chargecode", user.getChargeCode());
			if(StringUtils.isNotEmpty(user.getDelChargeCode())) {
				r.set("delChargeCode", user.getDelChargeCode());
			}
			Db.save("wx_order", "orderId", r);
	}
	
	/**
	 * 更新状态
	 * @param orderId
	 * @param state
	 */
	public void updateWxOrderState(String orderId,String state) {
		Record record = new Record();
		record.set("orderId", orderId);
		record.set("pay_code", state);
		Db.update("wx_order", "orderId", record);
	}
	
	public boolean saveWxOrderLog(final PayResult data) throws SQLException{
		synchronized (this) {
			return Db.tx(new IAtom() {
				@Override
				public boolean run() throws SQLException {
					PayOrder payOrder = getWxOrder(data.getOutTradeNo());
					//首先取订单，去不到说明已经处理过了，不做操作
					if(null!=payOrder) {
						if(StringUtils.isNotEmpty(payOrder.getDelChargeCode())) {
							delChargeOrder(payOrder);//删除体验套餐
						}
						deleteWxOrder(payOrder.getOrderId());//删除订单
						openCharge(payOrder, data.getTimeEnd());//开通套餐
						saveWxOrderLog(payOrder,data);//保存记录到订单日志表中
					}
					return true;
				}
			});
		}
	}
	
	public String getApiKey(String mchId) {
		String apiKey = null;
		Record record = Db.findFirst("select apikey from org_wxconfig where mchid=?",mchId);
		if(null!=record) {
			apiKey = record.getStr("apikey");
		}
		return apiKey;
	}
	
	private void deleteWxOrder(String orderId) {
		Db.deleteById("wx_order", "orderId", orderId);
	}
	
	/**
	 * 根据体验套餐编号和开通人信息获得套餐id
	 * @return
	 */
	private void delChargeOrder(PayOrder payOrder){
		List<Record> list = Db.find("select * from xzd_base_chargeorder where schoolid=? and stuid=? and chargecode=?",
				payOrder.getOrgid(),payOrder.getStuid(),payOrder.getDelChargeCode());
		if(!list.isEmpty()) {
			String orderid;
			Record data;
			for (Record r : list) {
				orderid = r.getStr("orderid");
				Db.deleteById("xzd_base_chargeorder", "orderid",orderid);
				data = r;
				data.remove("orderid");
				data.set("modify_time", new Date(System.currentTimeMillis()));
				data.set("historyid", orderid);
				data.set("orderremarks", "微信支付时移除");
				Db.save("xzd_base_chargehistory", "orderid", data);
			}
			try {
				RedisMgr.getInstance().del("sf_fm_stu_"+payOrder.getStuid());
				RedisMgr.getInstance().del("sf_fm_par_"+payOrder.getPersonid());
				RedisMgr.getInstance().del("charge_schoolid_"+payOrder.getOrgid()+"_stuid_"+payOrder.getStuid());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	private PayOrder getWxOrder(String orderId) {
		PayOrder data = null;
		Record r = Db.findById("wx_order", "orderId", orderId);
		if(null!=r) {
			data = new PayOrder(); 
			data.setOrderId(r.getStr("orderId"));
			data.setMchId(r.getStr("mchId"));
			data.setChargecode(r.getStr("chargecode"));
			data.setIpAddress(r.getStr("ipAddress"));
			data.setMobile(r.getStr("mobile"));
			data.setOpenid(r.getStr("openid"));
			data.setOrderDays(r.getInt("orderDays"));
			data.setOrgid(r.getStr("orgid"));
			data.setPayAmount(r.getLong("payAmount"));
			data.setPersonid(r.getStr("personid"));
			data.setPwxorgid(r.getStr("pwxorgid"));
			data.setStuid(r.getStr("stuid"));
			data.setTimeStart(r.getDate("time_start"));
			data.setWxorgid(r.getStr("wxorgid"));
			data.setDelChargeCode(r.getStr("delChargeCode"));
		}
		return data;
	}
	
	private void saveWxOrderLog(PayOrder payOrder,PayResult data) {
		Record record = new Record();
		record.set("logid", UUID.randomUUID().toString());
		if(null!=payOrder) {
			record.set("orderId", payOrder.getOrderId());
			record.set("mchId", payOrder.getMchId());
			record.set("personid", payOrder.getPersonid());
			record.set("openid", payOrder.getOpenid());
			record.set("mobile", payOrder.getMobile());
			record.set("orderDays",payOrder.getOrderDays());
			record.set("payAmount", payOrder.getPayAmount());
			record.set("ipAddress", payOrder.getIpAddress());
			record.set("time_start", payOrder.getTimeStart());
			record.set("chargecode", payOrder.getChargecode());
			record.set("stuid", payOrder.getStuid());
			record.set("pwxorgid", payOrder.getPwxorgid());
			record.set("orgid", payOrder.getOrgid());
			record.set("wxorgid", payOrder.getWxorgid());
		}
		StringBuilder str = new StringBuilder();
		record.set("time_end", data.getTimeEnd());
		record.set("result_code", data.getResultCode());
		record.set("receiptTime", new Date(System.currentTimeMillis()));
		record.set("bankType", data.getBankType());
		if(null!=payOrder) {
			if(!data.getMchId().equals(payOrder.getMchId())) {
				str.append("商户号不一致，提交订单商户号：　"+payOrder.getMchId()+",微信端返回商户号: "+data.getMchId());
			}
			if(data.getTotalFee()!=payOrder.getPayAmount()) {
				str.append("支付金额不一致，提交订单金额：　"+payOrder.getPayAmount()+",微信端返回金额: "+data.getTotalFee());
			}
			if(str.length()>0) {
				record.set("note", str.toString());
			}
		}
		record.set("transactionId",data.getTransactionId());
		Db.save("wx_order_log","logid",record);
	}
	
	/**
	 * 开通套餐
	 * @throws SQLException 
	 */
	private void openCharge(PayOrder payOrder,Date endTime) throws SQLException {
		boolean b = isChargeOrder(payOrder,endTime);
		if(b) {
			//已经开通无需在开通
			return;
		}
		Date ordertime = getLastChargeTime(payOrder.getOrgid(), payOrder.getStuid(), payOrder.getPersonid(), payOrder.getChargecode());
		if(null==ordertime) {
			ordertime = endTime;//查询没有开通的记录，那么按照支付完成时间来开通套餐
		}
		Integer days = payOrder.getOrderDays();
		Date orderFail = getEndTime(ordertime, days);
		String tclx = getTclx(payOrder.getChargecode());
		openChargeOrder(payOrder, ordertime, orderFail, tclx);
	}
	
	/**
	 * 套餐最后一次的实效时间
	 * @param schoolid
	 * @param stuid
	 * @param parid
	 * @param chargeCode
	 * @return
	 */
	private Date getLastChargeTime(String schoolid,String stuid,String parid,String chargeCode) {
		Date orderfail = null;
		Record record = Db.findFirst("select orderfail from xzd_base_chargeorder where schoolid=? and stuid=? and parid=? and chargecode=? order by orderfail desc", schoolid,stuid,parid,chargeCode);
		if(null!=record) {
			orderfail = record.getDate("orderfail");
		}
		return orderfail;
	}
	/**
	 * 判断当前套餐是否已经村咋，存在就不用在开通了
	 * @return
	 */
	private boolean isChargeOrder(PayOrder payOrder,Date endTime) {
		Long count = Db.queryLong("select count(*) from xzd_base_chargeorder where schoolid=? and stuid=? and parid=? and chargecode=? and ordertime=?",payOrder.getOrgid(),payOrder.getStuid(),payOrder.getPersonid(),payOrder.getChargecode(),endTime);
		return count>0?true:false;
	}
	/**
	 * 开通套餐
	 * @param payOrder
	 * @param orderTime
	 * @param orderFail
	 * @param tclx
	 * @throws SQLException
	 */
	private void openChargeOrder(PayOrder payOrder,Date orderTime,Date orderFail,String tclx) throws SQLException{
		Record r = new Record();
		r.set("orderid", UUID.randomUUID().toString().replaceAll("-", ""));
		r.set("orderphone", payOrder.getMobile());
		r.set("ordertime", orderTime);
		r.set("orderfail", orderFail);
		r.set("orderremarks", "通过微信支付开通套餐");
		r.set("modify_time", new Date(System.currentTimeMillis()));
		r.set("tclx", tclx);
		r.set("schoolid", payOrder.getOrgid());
		r.set("parid", payOrder.getPersonid());
		r.set("chargecode", payOrder.getChargecode());
		r.set("stuid", payOrder.getStuid());
		boolean b = Db.save("xzd_base_chargeorder", "orderid", r);
		if(!b) {
			throw new SQLException("开通套餐失败!");
		}
	}
	
	private Date getEndTime(Date date,Integer days) throws SQLException {
		Calendar c = Calendar.getInstance();
		c.setTime(date); 
		c.add(Calendar.DAY_OF_MONTH, days);
		return c.getTime();
	}
	
	private String getTclx(String chargeCode) {
		String tclx = null;
		String id="baseCharge_"+chargeCode;
		try {
			String prop = RedisMgr.getInstance().getProp(id);
			if(StringUtils.isEmpty(prop)) {
				Record r = getXzdBaseCharge(chargeCode);
				if(null!=r) {
					tclx = r.getStr("tclx");
					JSONObject j = new JSONObject();
					j.put("chargecode", r.getStr("chargecode"));
					j.put("chargename", r.getStr("chargename"));
					j.put("tclx",tclx);
					j.put("chargeprice", r.getDouble("chargeprice"));
					j.put("info", r.getStr("info"));
					RedisMgr.getInstance().setProp(id, j.toJSONString());
				}
				
			}else {
				JSONObject jo = JSON.parseObject(prop);
				tclx = jo.getString("tclx");
			}
		} catch (ClassNotFoundException | IOException e) {
			e.printStackTrace();
		}
		return tclx;
	}
	
	
	private Record getXzdBaseCharge(String chargecode) {
		return Db.findById("xzd_base_charge", "chargecode", chargecode);
	}
}